﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Common.Constants;
using Common.Helper;
using Common.Interface;

namespace MainProcessor.Validation
{
    public class ChildValidation : IValidateInput
    {
        private readonly IEntityFactory entityFactory;
        private readonly List<Func<XElement, string>> validators;
        

        public ChildValidation(IEntityFactory entityFactory)
        {
            this.entityFactory = entityFactory;
            validators = new List<Func<XElement, string>>
                             {
                                 ValidateHeimdallHeimdallGuidIsAGuid,
                                 ValidateOnly1Master,
                             };
        }

        public string Validate(XElement message)
        {
            return validators.Aggregate(String.Empty, (x, y) =>
                                                          {
                                                              var result = y(message);
                                                              if (result.Length > 0)
                                                                  x = x + result + Environment.NewLine;
                                                              return x;
                                                          });
        }

        private string ValidateHeimdallHeimdallGuidIsAGuid(XElement message)
        {
            Guid outputGuid;
            var errors = (from el in entityFactory.CreateChildren(message)
                          let childGuid = el.BaseElement.Element(XmlConstants.ChildGuid)
                          let childName = el.BaseElement.Element(XmlConstants.ChildName)
                          
                          where childGuid.IsNullOrEmpty() == false && Guid.TryParse(childGuid.Value, out outputGuid) == false
                          select string.Format("Validation failed for Child with name '{0}'. Reason: Child Guid '{1}' is not a Guid", childName.IsNullOrEmpty() ? string.Empty : childName.Value, childGuid.Value));

            return String.Join(Environment.NewLine, errors);
        }

        private string ValidateOnly1Master(XElement message)
        {
            var manyMasters = (from parentContainer in message.Descendants(XmlConstants.ParentContainer)
                               let mappedId = parentContainer.Element(XmlConstants.MappingId)
                               from el in entityFactory.CreateChildren(parentContainer)
                               let isMaster = el.BaseElement.Element(XmlConstants.IsMaster)
                               let childGuid = el.BaseElement.Element(XmlConstants.ChildGuid)
                               let childName = el.BaseElement.Element(XmlConstants.ChildName)
                               where isMaster.IsNullOrEmpty() == false && Convert.ToBoolean(isMaster.Value)
                               group new { childGuid, isMaster, childName } by mappedId.Value
                                   into masters
                                   where masters.Count() > 1
                                   select string.Format("Validation Failed for Mapped ID {0}, It has more than one master child, {1} ;", masters.Key,
                                   masters.Aggregate(string.Empty, (w, z) => w + (" mapping Id '" + z.childGuid + "', Name: '" + (z.childName.IsNullOrEmpty() ? string.Empty : z.childName.Value) + "'"))));
            return string.Join(Environment.NewLine, manyMasters);
        }
        
    }
}
